package com.jiangtour.service.impl;

import com.jiangtour.VO.SiteInfoVO;
import com.jiangtour.VO.UserInfoVO;
import com.jiangtour.constant.CookieConstant;
import com.jiangtour.constant.RedisConstant;
import com.jiangtour.dataobject.*;
import com.jiangtour.dto.*;
import com.jiangtour.enums.ConfigureEnum;
import com.jiangtour.enums.ResultEnum;
import com.jiangtour.enums.UseStatusEnum;
import com.jiangtour.exception.SiteException;
import com.jiangtour.repository.ConfigureCategoryRepository;
import com.jiangtour.repository.ProductCategoryRepository;
import com.jiangtour.repository.SiteInfoRepository;
import com.jiangtour.repository.UserInfoRepository;
import com.jiangtour.service.SiteInfoService;
import com.jiangtour.utils.CookieUtil;
import com.jiangtour.utils.KeyUtil;
import com.jiangtour.utils.MD5;
import com.jiangtour.utils.Numbers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.security.Key;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @Title: SiteInfoServiceImpl
 * @ProjectName site
 * @Description:
 * @date 2018/12/25/02516:51
 */

@Service
@Slf4j
public class SiteInfoServiceImpl  implements SiteInfoService {

    @Autowired
    private SiteInfoRepository siteInfoRepository;
    @Autowired
    private ConfigureCategoryRepository configureCategoryRepository;
    @Autowired
    private ProductCategoryRepository productCategoryRepository;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserInfoRepository userInfoRepository;


    @Override
    public Page<SiteInfo> findList(Pageable pageable) {
       Page<SiteInfo> page= siteInfoRepository.findAll(pageable);
        return new PageImpl<>(page.getContent(),pageable,page.getTotalElements());
    }

    @Override
    public SiteInfo findOne(String id) {
        return siteInfoRepository.findById(id).get();
    }

    @Override
    public SiteInfo create(SiteInfo siteInfo) {

        siteInfo.setServiceAmount(new BigDecimal(2.0));
        return siteInfoRepository.save(siteInfo);
    }

    @Override
    public SiteInfo onUse(String siteId) {

        SiteInfo siteInfo = siteInfoRepository.findById(siteId).get();
        if(siteInfo ==null ){
            throw  new SiteException(ResultEnum.SITE_NOT_EXIST);
        }
        if(siteInfo.getUseStatusEnum()==UseStatusEnum.USE){
            throw  new SiteException(ResultEnum.SITE_STATUS_ERROR);
        }
        //更新
        siteInfo.setUseStatus(UseStatusEnum.USE.getCode());
        return siteInfoRepository.save(siteInfo);
    }

    @Override
    public SiteInfo offUse(String siteId) {
        SiteInfo siteInfo = siteInfoRepository.findById(siteId).get();
        if(siteInfo ==null ){
            throw  new SiteException(ResultEnum.SITE_NOT_EXIST);
        }
        if(siteInfo.getUseStatusEnum()==UseStatusEnum.PROHIBIT){
            throw  new SiteException(ResultEnum.SITE_STATUS_ERROR);
        }
        //更新
        siteInfo.setUseStatus(UseStatusEnum.PROHIBIT.getCode());
        return siteInfoRepository.save(siteInfo);
    }

    @Override
    public SiteDTO findSiteByDistance(double lng, double lat,String siteId) {
        SiteInfo siteInfo =new SiteInfo();
        if(siteId ==null || StringUtils.isEmpty(siteId)){
            //1.根据经纬度获取一个最近的地址默认
            List<SiteInfo> distanceByLonAndLat = siteInfoRepository.findDistanceByLonAndLat(lng, lat);
            if(CollectionUtils.isEmpty(distanceByLonAndLat)){
                log.error("经纬度附近没有站点,distanceByLonAndLat={},"+distanceByLonAndLat);
                throw  new SiteException(ResultEnum.SITE_NOT_FIND);
            }
            siteInfo = distanceByLonAndLat.get(0);

        }else {
            siteInfo=siteInfoRepository.getOne(siteId);
        }

        //2.根据选中的站点返回默认信息

         //楼号
        List<ConfigureCategory> buildList = configureCategoryRepository.findByCategoryAscriptionList(siteInfo.getId(), ConfigureEnum.FLOOR.getCode());
        List<BuildingNumberDTO> buildingNumberDTOS = buildList.stream().map(e -> new BuildingNumberDTO(e.getCategoryId(), e.getCategoryName())).collect(Collectors.toList());

        //快递
        List<ConfigureCategory> exoressList =configureCategoryRepository.findByCategoryAscriptionList(siteInfo.getId(), ConfigureEnum.EXPRESS.getCode());
        List<ExpressDTO> expressDTOS = exoressList.stream().map(e -> new ExpressDTO(e.getCategoryId(), e.getCategoryName())).collect(Collectors.toList());

        //快件点
        List<ConfigureCategory> pointList = configureCategoryRepository.findByCategoryAscriptionList(siteInfo.getId(), ConfigureEnum.PICKING_POINT.getCode());
        List<PointDTO> pointDTOS = pointList.stream().map(e -> new PointDTO(e.getCategoryId(), e.getCategoryName())).collect(Collectors.toList());

        //规格
        List<ProductCategory> productCategoryList = productCategoryRepository.findByCategoryAscription(siteInfo.getId());
        List<SpecificationsDTO> specificationsDTOS = productCategoryList.stream().map(e -> new SpecificationsDTO(e.getCategoryId(), e.getCategoryName(), e.getCategoryAmount())).collect(Collectors.toList());

        SiteDTO siteDTO = new SiteDTO();
        siteDTO.setBuildingNumberDTOList(buildingNumberDTOS);
        siteDTO.setExpressDTOList(expressDTOS);
        siteDTO.setPointDTOList(pointDTOS);
        siteDTO.setSpecificationsDTOList(specificationsDTOS);
        siteDTO.setServiceAmount(siteInfo.getServiceAmount());
        siteDTO.setSiteId(siteInfo.getId());

        return siteDTO;
    }

    @Override
    public List<SiteInfo> findAllSite() {
        return siteInfoRepository.findAll(new Specification<SiteInfo>() {
            @Override
            public Predicate toPredicate(Root<SiteInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();
                predicate.getExpressions().add(criteriaBuilder.equal(root.get("useStatus"),UseStatusEnum.USE.getCode()));
                return predicate;
            }
        });
    }

    @Override
    public SiteInfo findCurrentAccount(HttpServletRequest request) {
        //1. 从cookie里查询
        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        //2.从redis中取出
        String account = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue()));
        //3.根据账号查询
        SiteInfo siteInfo = siteInfoRepository.findByAccount(account);

        return siteInfo;
    }

    @Override
    public UserInfoVO findUserByPhone(String phone) {
        UserInfo userInfo = userInfoRepository.findByPhone(phone);

        UserInfoVO userInfoVO = new UserInfoVO();
        if(userInfo !=null ){
            userInfoVO.setAddress(userInfo.getAddress());
            userInfoVO.setFloorId(userInfo.getBuildId());
            userInfoVO.setUserName(userInfo.getUserName());
        }
        return userInfoVO;
    }

    @Override
    public void saveOrUpdate(OrderMaster orderMaster) {
        UserInfo userInfo =  userInfoRepository.findByPhone(orderMaster.getBuyerPhone());
        if(userInfo !=null ){
            userInfo.setBuildId(orderMaster.getFloorNumber());
            userInfo.setUserName(orderMaster.getBuyerName());
            userInfo.setPhone(orderMaster.getBuyerPhone());
            userInfo.setAddress(orderMaster.getBuyerAddress());
            userInfo.setAscription(orderMaster.getAscriptionId());
            userInfo.setUpdateTime(new Date());
            userInfoRepository.save(userInfo);
        }else{
            UserInfo info = new UserInfo();
            info.setBuildId(orderMaster.getFloorNumber());
            info.setUserName(orderMaster.getBuyerName());
            info.setPhone(orderMaster.getBuyerPhone());
            info.setAddress(orderMaster.getBuyerAddress());
            info.setAscription(orderMaster.getAscriptionId());
            info.setUserId(KeyUtil.getUniqueKey());
            info.setCreateTime(new Date());
            info.setUpdateTime(new Date());
            userInfoRepository.save(info);
        }

    }

    @Override
    public SiteInfo login(String account, String password) {

        if(account.equals("admin")){
            if(! password.equals("123456")){
                log.info("登陆失败={},密码错误",account);
                throw new SiteException(ResultEnum.PASSWORD_ERROR);
            }
        }else {
            SiteInfo siteInfo = siteInfoRepository.findByAccount(account.trim());
            if(siteInfo==null ){
                log.info("登陆失败={}",account);
                throw new SiteException(ResultEnum.PASSWORD_ERROR);
            }

            if(!MD5.MD5Encode(password.trim()+siteInfo.getSalt()).equals(siteInfo.getPassword())){
                log.info("登陆失败={},密码错误",account);
                throw new SiteException(ResultEnum.PASSWORD_ERROR);
            }

            if(siteInfo.getUseStatus()==UseStatusEnum.PROHIBIT.getCode()){
                throw new SiteException(ResultEnum.SITE_STATUS_UNABLE);
            }
            log.info("登陆成功={}",siteInfo.getAccount());
            return siteInfo;

        }
        return  null;
    }

    @Override
    public void updatePassword(String siteId, String password) {
        SiteInfo siteInfo = siteInfoRepository.getOne(siteId);
        if(siteInfo ==null ){
            throw new SiteException(ResultEnum.SITE_NOT_EXIST);
        }
        //密码加盐
        siteInfo.setSalt("salt_" + Numbers.sortUUID());
        siteInfo.setPassword(MD5.MD5Encode(password + siteInfo.getSalt()));
        siteInfoRepository.save(siteInfo);

    }

    @Override
    public SiteInfo queryByAccount(String account) {
        return siteInfoRepository.findByAccount(account);
    }
}
